#include <iostream>
#include <unistd.h>
#include "circularqueue.hpp"
#include "Task.hpp"
using namespace std;

#include <ctime>
#include <string>
#define CNUM 3
#define PNUM 5
const string opers = "+-*/%";

//using Data = int;
using Data = Task; //typedef
//维护显示器资源
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
bool isfree = true;

void* Consumer(void* args)
{
    CircularQueue<Data> *cq = static_cast<CircularQueue<Data>*>(args);
    while(true)
    {
        //1、获取数据
        usleep(100);

        //2、消费数据 —> 对数据进行处理
        Data t;
        cq->Pop(&t); //先消费，千万不要放在后面的锁之中！
        t(); //跑一下数据
        
        pthread_mutex_lock(&mutex);
        while(!isfree)
            pthread_cond_wait(&cond, &mutex);
        
        isfree = false;
        //cout << "消费者开始消费数据：" << t << " 消费者编号：" << pthread_self() << endl; //显示器资源需要维护
        std::cout << "处理任务: " << t.GetTask() << " 运算结果是：" 
            << t.GetResult() << " thread id: " << pthread_self() << std::endl;
        isfree = true;

        pthread_mutex_unlock(&mutex); //先解锁再唤醒
        pthread_cond_signal(&cond);
        //cout << "开始消费……" << endl;
        sleep(1);
    }

    return nullptr;
}

void* Productor(void* args)
{
    CircularQueue<Data> *cq = static_cast<CircularQueue<Data>*>(args);
    int cnt = 2;
    while(cnt--)
    {
        //1、获取数据
        usleep(100);

        //2、生产数据
        //Data t = rand() % 10;
        Data t = Data(rand() % 10, opers[rand() % (opers.size())], rand() % 10);
        cq->Push(t); //先生产，千万不要放在后面的锁之中！

        pthread_mutex_lock(&mutex);
        while(!isfree)
            pthread_cond_wait(&cond, &mutex);
        
        isfree = false;
        //cout << "生产者开始生产数据：" << t << " 生产者编号：" << pthread_self() << endl;
        std::cout << "生产了一个任务: " << t.GetTask() << " thread id: " << pthread_self() << std::endl;
        isfree = true;

        pthread_mutex_unlock(&mutex); //先解锁再唤醒
        pthread_cond_signal(&cond);
        //cout << "开始生产……" << endl;
        sleep(1);
    }

    return nullptr;
}

int main()
{
    srand((unsigned int)time(nullptr) ^ 0x35534d5);
    CircularQueue<Data> *cq = new CircularQueue<Data>();

    pthread_t c[CNUM], p[PNUM];
    for(int i = 0; i < CNUM; i++)
    {
        pthread_create(c + i, nullptr, Consumer, cq);
    }
    for(int i = 0; i < PNUM; i++)
    {
        pthread_create(p + i, nullptr, Productor, cq);
    }
    //线程等待
    for(int i = 0; i < CNUM; i++)
    {
        pthread_join(c[i], nullptr);
    }
    for(int i = 0; i < PNUM; i++)
    {
        pthread_join(p[i], nullptr);
    }

    delete cq;
    return 0;
}